#include "StdAfx.h"
#include "MyPosPassThru.h"


// --- IMediaPosition and IMediaSeeking pass through class ----------


CMyPosPassThru::CMyPosPassThru(const TCHAR *pName,
						   LPUNKNOWN pUnk,
						   HRESULT *phr,
						   IPin *pPin,
						   IPin *pPin2):
CMediaPosition(pName,pUnk)
,m_pPin(pPin)
,m_pPin2(pPin2)
,m_rtStart(0)
,m_rtStop(0)
{
	if (pPin == NULL && pPin2 == NULL) {
		*phr = E_POINTER;
		return;
	}

}


// Expose our IMediaSeeking and IMediaPosition interfaces

STDMETHODIMP
CMyPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv)
{
	CheckPointer(ppv,E_POINTER);
	*ppv = NULL;

	if (riid == IID_IMediaSeeking) {
		return GetInterface( static_cast<IMediaSeeking *>(this), ppv);
	}
	return CMediaPosition::NonDelegatingQueryInterface(riid,ppv);
}


// Return the IMediaPosition interface from our peer

HRESULT
CMyPosPassThru::GetPeer(IMediaPosition ** ppMP)
{
	*ppMP = NULL;

	IPin *pConnected;
	HRESULT hr = m_pPin->ConnectedTo(&pConnected);
	if (FAILED(hr)) {
		hr = m_pPin2->ConnectedTo(&pConnected);
		if(FAILED(hr))
			return E_NOTIMPL;
	}
	IMediaPosition * pMP;
	hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
	pConnected->Release();
	if (FAILED(hr)) {
		return E_NOTIMPL;
	}

	*ppMP = pMP;
	return S_OK;
}


// Return the IMediaSeeking interface from our peer

HRESULT
CMyPosPassThru::GetPeerSeeking(IMediaSeeking ** ppMS)
{
	*ppMS = NULL;

	IPin *pConnected;
	HRESULT hr = m_pPin->ConnectedTo(&pConnected);
	if (FAILED(hr)) {
		hr = m_pPin2->ConnectedTo(&pConnected);
		if(FAILED(hr)){
			return E_NOTIMPL;
		}
	}
	IMediaSeeking * pMS;
	hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS);
	pConnected->Release();
	if (FAILED(hr)) {
		return E_NOTIMPL;
	}

	*ppMS = pMS;
	return S_OK;
}


// --- IMediaSeeking methods ----------


STDMETHODIMP
CMyPosPassThru::GetCapabilities(DWORD * pCaps)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->GetCapabilities(pCaps);
	pMS->Release();
	return hr;
}

STDMETHODIMP
CMyPosPassThru::CheckCapabilities(DWORD * pCaps)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->CheckCapabilities(pCaps);
	pMS->Release();
	return hr;
}

STDMETHODIMP
CMyPosPassThru::IsFormatSupported(const GUID * pFormat)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->IsFormatSupported(pFormat);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::QueryPreferredFormat(GUID *pFormat)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->QueryPreferredFormat(pFormat);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::SetTimeFormat(const GUID * pFormat)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->SetTimeFormat(pFormat);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::GetTimeFormat(GUID *pFormat)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->GetTimeFormat(pFormat);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::IsUsingTimeFormat(const GUID * pFormat)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->IsUsingTimeFormat(pFormat);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat,
								LONGLONG    Source, const GUID * pSourceFormat )
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat );
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags
						   , LONGLONG * pStop, DWORD StopFlags )
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags );
	pMS->Release();
	return hr;
}

STDMETHODIMP
CMyPosPassThru::GetPositions(LONGLONG *pCurrent, LONGLONG * pStop)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->GetPositions(pCurrent,pStop);
	pMS->Release();
	return hr;
}

HRESULT
CMyPosPassThru::GetSeekingLongLong
( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * )
 , LONGLONG * pll
 )
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (SUCCEEDED(hr))
	{
		hr = (pMS->*pMethod)(pll);
		pMS->Release();
	}
	return hr;
}

// If we don't have a current position then ask upstream

STDMETHODIMP
CMyPosPassThru::GetCurrentPosition(LONGLONG *pCurrent)
{
	// Can we report the current position
	HRESULT hr = GetMediaTime(pCurrent,NULL);
	if (SUCCEEDED(hr)) hr = NOERROR;
	else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent );
	return hr;
}


STDMETHODIMP
CMyPosPassThru::GetStopPosition(LONGLONG *pStop)
{
	return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
}

STDMETHODIMP
CMyPosPassThru::GetDuration(LONGLONG *pDuration)
{
	return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
}


STDMETHODIMP
CMyPosPassThru::GetPreroll(LONGLONG *pllPreroll)
{
	return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
}


STDMETHODIMP
CMyPosPassThru::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest )
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMS->GetAvailable( pEarliest, pLatest );
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::GetRate(double * pdRate)
{
	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMS->GetRate(pdRate);
	pMS->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::SetRate(double dRate)
{
	if (0.0 == dRate) {
		return E_INVALIDARG;
	}

	IMediaSeeking* pMS;
	HRESULT hr = GetPeerSeeking(&pMS);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMS->SetRate(dRate);
	pMS->Release();
	return hr;
}




// --- IMediaPosition methods ----------


STDMETHODIMP
CMyPosPassThru::get_Duration(REFTIME * plength)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}

	hr = pMP->get_Duration(plength);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::get_CurrentPosition(REFTIME * pllTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->get_CurrentPosition(pllTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::put_CurrentPosition(REFTIME llTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->put_CurrentPosition(llTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::get_StopTime(REFTIME * pllTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->get_StopTime(pllTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::put_StopTime(REFTIME llTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->put_StopTime(llTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::get_PrerollTime(REFTIME * pllTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->get_PrerollTime(pllTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::put_PrerollTime(REFTIME llTime)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->put_PrerollTime(llTime);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::get_Rate(double * pdRate)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->get_Rate(pdRate);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::put_Rate(double dRate)
{
	if (0.0 == dRate) {
		return E_INVALIDARG;
	}

	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->put_Rate(dRate);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::CanSeekForward(LONG *pCanSeekForward)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->CanSeekForward(pCanSeekForward);
	pMP->Release();
	return hr;
}


STDMETHODIMP
CMyPosPassThru::CanSeekBackward(LONG *pCanSeekBackward)
{
	IMediaPosition* pMP;
	HRESULT hr = GetPeer(&pMP);
	if (FAILED(hr)) {
		return hr;
	}
	hr = pMP->CanSeekBackward(pCanSeekBackward);
	pMP->Release();
	return hr;
}

HRESULT 
CMyPosPassThru::RegisterMediaTime(LONGLONG rtStart, LONGLONG rtEnd)
{
	m_rtStart = rtStart;
	m_rtStop = rtEnd;
	m_bReset = false;
	return S_OK;
}

HRESULT
CMyPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime)
{
	CAutoLock cAutoLock(&m_PositionLock);
	if (m_bReset == true) {
		return E_FAIL;
	}

	// We don't have to return the end time

	HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_rtStart, &TIME_FORMAT_MEDIA_TIME );
	if (pEndTime && SUCCEEDED(hr)) {
		hr = ConvertTimeFormat( pEndTime, 0, m_rtStop, &TIME_FORMAT_MEDIA_TIME );
	}
	return hr;
}

HRESULT 
CMyPosPassThru::ResetMediaTime()
{
	CAutoLock lock(&m_PositionLock);
	m_rtStart = m_rtStop = 0;
	m_bReset = true;
	return NOERROR;
}

HRESULT 
CMyPosPassThru::EOS()
{
	HRESULT hr;

	if ( m_bReset == true ) hr = E_FAIL;
	else
	{
		LONGLONG llStop;
		if SUCCEEDED(hr=GetStopPosition(&llStop))
		{
			CAutoLock cAutoLock(&m_PositionLock);
			m_rtStart = m_rtStop  = llStop;
		}
	}
	return hr;
}


